/**
 * 
 */
package fr.gfi.agraf.service.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import fr.gfi.agraf.exception.AgrafException;
import fr.gfi.agraf.persistence.dao.IActiviteDAO;
import fr.gfi.agraf.persistence.dao.IEtatDAO;
import fr.gfi.agraf.persistence.dao.IPerimetreDAO;
import fr.gfi.agraf.persistence.entity.Activite;
import fr.gfi.agraf.persistence.entity.Etat;
import fr.gfi.agraf.persistence.entity.Perimetre;
import fr.gfi.agraf.service.IActiviteService;
import fr.gfi.agraf.service.mapper.ActiviteMapper;
import fr.gfi.agraf.service.mapper.PerimetreMapper;
import fr.gfi.agraf.vue.bean.ActiviteDTO;
import fr.gfi.agraf.vue.bean.DonneesAjaxActivitesByPerimetre;

/**
 * @author Fw
 * 
 */
@Service("ActiviteService")
@Transactional(propagation = Propagation.REQUIRED)
public class ActiviteService implements IActiviteService {

	private static final String ERREUR_ACTIVITE_IMPOSSIBLE_SUPPRIMER = "erreur.activite.impossible.supprimer";

	@Autowired
	private IActiviteDAO activiteDAO;

	@Autowired
	private IPerimetreDAO perimetreDAO;

	@Autowired
	private IEtatDAO etatDAO;

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * fr.gfi.agraf.service.IActiviteService#getListeActivitesByPerimetre(java
	 * .lang.Long)
	 */
	public DonneesAjaxActivitesByPerimetre getListeActivitesByPerimetreAndUtilisateur(final Long idPerimetre,
			final Long idUtilisateur) {
		final DonneesAjaxActivitesByPerimetre output = new DonneesAjaxActivitesByPerimetre();

		// Ajout de la liste d'activite
		final List<Activite> listeRecup = activiteDAO.getListeActivitesByPerimetreAndUtilisateur(idPerimetre,
				idUtilisateur);
		final List<ActiviteDTO> listeActivitesOutput = new ArrayList<ActiviteDTO>();
		for (final Activite activite : listeRecup) {
			listeActivitesOutput.add(ActiviteMapper.getDtoByEntity(activite,null));
		}
		output.setListeActiviteDTO(listeActivitesOutput);

		// Ajout du perimetre concerné
		final Perimetre perimetreOutput = perimetreDAO.read(idPerimetre);
		output.setPerimetreDTO(PerimetreMapper.entityToDto(perimetreOutput));

		return output;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * fr.gfi.agraf.service.IActiviteService#modifierPerimetreFromIHM(java.lang
	 * .String, java.util.List, java.util.List)
	 */
	public void modifierPerimetreFromIHM(final Long idPerimetre, final String libellePerimetre,
			final List<Long> listeIdActiviteToDelete, final List<ActiviteDTO> listeActiviteToModif,
			final List<ActiviteDTO> listeNouvellesActivites) throws AgrafException {

		final Map<Long, Etat> etatMap = etatDAO.getEtatsMap();

		// Je gere la sauvegarde du périmetre
		final Perimetre perimetre = perimetreDAO.read(idPerimetre);
		perimetre.setLibelle(libellePerimetre);
		final Set<Activite> activiteSet = perimetre.getActiviteSet();

		// Je gere la suppression des activités
		if (listeIdActiviteToDelete != null) {
			final Set<Activite> actToRemoveSet = verifieActiviteToRemove(listeIdActiviteToDelete, activiteSet);
			activiteSet.removeAll(actToRemoveSet);
		}

		// Je gere le merge des activites
		if (listeActiviteToModif != null) {
			traitementActiviteToUpdate(listeActiviteToModif, activiteSet);
		}

		// Puis je gere les nouvelles activités
		if (listeNouvellesActivites != null) {
			traitementActiviteToCreate(listeNouvellesActivites, etatMap, perimetre, activiteSet);
		}
		perimetreDAO.update(perimetre);
	}

	/**
	 * Creer les activites pour un perimetre
	 * 
	 * @param listeNouvellesActivites
	 * @param etatMap
	 * @param perimetre
	 * @param activiteSet
	 */
	private void traitementActiviteToCreate(final List<ActiviteDTO> listeNouvellesActivites,
			final Map<Long, Etat> etatMap, final Perimetre perimetre, final Set<Activite> activiteSet) {
		// pour chaque DTO on créé une entity
		for (final ActiviteDTO actToAdd : listeNouvellesActivites) {
			final Activite activite = new Activite();
			final Etat etat = etatMap.get(actToAdd.getEtat().getId());
			activite.setDateCreation(actToAdd.getDateCreation());
			activite.setEtat(etat);
			activite.setLibelle(actToAdd.getLibelle());
			activite.setRemarque(actToAdd.getRemarque());
			// Je leurs ajoute le perimetre
			activite.setPerimetre(perimetre);
			activiteSet.add(activite);

		}
	}

	/**
	 * Modifie les activites pour un perimetre
	 * 
	 * @param listeActiviteToModif
	 * @param activiteSet
	 */
	private void traitementActiviteToUpdate(final List<ActiviteDTO> listeActiviteToModif,
			final Set<Activite> activiteSet) {
		// parcours la liste afin de récuperer l'entity et on l'a modifie
		for (final ActiviteDTO actToUpdate : listeActiviteToModif) {
			for (final Activite activite : activiteSet) {
				if (actToUpdate.getId().equals(activite.getId())) {
					activite.setLibelle(actToUpdate.getLibelle());
					activite.setRemarque(actToUpdate.getRemarque());
				}
			}
		}
	}

	/**
	 * Verifie si l'activité peut être supprimé et retourne la liste à supprimer
	 * 
	 * @param listeIdActiviteToDelete
	 * @param perimetre
	 * @return
	 * @throws AgrafException
	 */
	private Set<Activite> verifieActiviteToRemove(final List<Long> listeIdActiviteToDelete,
			final Set<Activite> activiteSet) throws AgrafException {
		final Set<Activite> actToRemoveSet = new HashSet<Activite>();
		// parcours la liste, si on peut supprimer on l'ajoute à la liste à
		// retourner, sinon on throw une exception
		for (final Long idActToRemove : listeIdActiviteToDelete) {
			for (final Activite activite : activiteSet) {
				if (idActToRemove.equals(activite.getId())) {
					if (CollectionUtils.isEmpty(activite.getTacheSet())) {
						actToRemoveSet.add(activite);
					} else {
						throw new AgrafException(ERREUR_ACTIVITE_IMPOSSIBLE_SUPPRIMER);
					}
				}
			}
		}
		return actToRemoveSet;
	}
}
